package com.iwhalecloud.citybrain.flow.platform.manager.application.service;

import java.util.Date;
import java.util.List;
import java.util.Objects;

import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.NodeOperEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.NodeOperEventTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.event.NodeOperEventCaller;
import com.iwhalecloud.citybrain.flow.platform.manager.application.event.NodeOperEventReq;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.common.utils.UUIDGenerator;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.ModelCustomConfigDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.CommentVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowReModelCustomConfigRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTaskTraceRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.IFlowableCommentService;
import org.flowable.engine.HistoryService;
import org.flowable.engine.IdentityService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class BaseProcessService {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    protected ManagementService managementService;
    @Autowired
    protected TaskService taskService;
    @Autowired
    protected RuntimeService runtimeService;
    @Autowired
    protected RepositoryService repositoryService;
    @Autowired
    protected HistoryService historyService;
    @Autowired
    protected IdentityService identityService;
    @Autowired
    protected IFlowableCommentService flowableCommentService;
    @Autowired
    protected FlowReModelCustomConfigRepository flowReModelCustomConfigRepository;

    @Autowired
    private FlowTaskTraceRepository flowTaskTraceRepository;

    @Autowired
    private NodeOperEventCaller nodeOperEventCaller;


    /**
     * 添加审批意见
     *
     * @param taskId            任务id
     * @param userCode          处理人工号
     * @param processInstanceId 流程实例id
     * @param type              审批类型
     * @param message           审批意见
     */
    public void addComment(String taskId, String userCode, String processInstanceId, String type, String message) {
        //1.添加备注
        CommentVo commentVo = new CommentVo(taskId, userCode, processInstanceId, type, message);
        flowableCommentService.addComment(commentVo);
    }

    /**
     * 转办消息发送
     *
     * @param taskId            任务id
     * @param userCode          处理人工号
     * @param processInstanceId 流程实例id
     * @param turnToUserCode    被转发的人工号
     */
    protected  void sendMessage(String taskId, String userCode, String processInstanceId, String turnToUserCode,String messageType,String title,String content){
        //消息发送
        flowableCommentService.sendMessage(taskId,userCode,processInstanceId,turnToUserCode,messageType,title,content);
    }

    protected TaskEntity createSubTask(Task ptask, String assignee) {
        return this.createSubTask(ptask, ptask.getId(), assignee);
    }

    /**
     * 创建子任务
     *
     * @param ptask    创建子任务
     * @param assignee 子任务的执行人
     * @return
     */
    protected TaskEntity createSubTask(Task ptask, String ptaskId, String assignee) {
        TaskEntity task = null;
        if (ptask != null) {
            //1.生成子任务
            task = (TaskEntity) taskService.newTask(UUIDGenerator.generate());
            task.setCategory(ptask.getCategory());
            task.setDescription(ptask.getDescription());
            task.setTenantId(ptask.getTenantId());
            task.setAssignee(assignee);
            task.setName(ptask.getName());
            task.setParentTaskId(ptaskId);
            task.setProcessDefinitionId(ptask.getProcessDefinitionId());
            task.setProcessInstanceId(ptask.getProcessInstanceId());
            task.setTaskDefinitionKey(ptask.getTaskDefinitionKey());
            task.setTaskDefinitionId(ptask.getTaskDefinitionId());
            task.setPriority(ptask.getPriority());
            task.setCreateTime(new Date());
            task.setFormKey(ptask.getFormKey());
            //task.setVariablesLocal(managementService.executeCommand(new GetTaskVariablesCmd(ptaskId, null, false)));
            taskService.saveTask(task);
        }
        return task;
    }


    public boolean isRequiredComment(String processInstanceId,String nodeCode){
        boolean flag = false;
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = processInstance.getProcessDefinitionId();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
        String deploymentId = processDefinition.getDeploymentId();
        List<ModelCustomConfigDomain> modelCustomConfigDomainList = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deploymentId,
                nodeCode, ConstanceVariable.IS_REQUIRED_COMMENT);
        if (Objects.nonNull(modelCustomConfigDomainList) && modelCustomConfigDomainList.size() > 0){
            for (ModelCustomConfigDomain modelCustomConfigDomain : modelCustomConfigDomainList) {
                String isRequiredComment = modelCustomConfigDomain.getConfig();
                if (Objects.equals(isRequiredComment,"1")){
                    flag = true;
                }
            }
        }
        return flag;
    }

    public boolean checkIsRequired(String processInstanceId,String nodeCode, String idea){
        boolean flag = false;
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = processInstance.getProcessDefinitionId();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
        String deploymentId = processDefinition.getDeploymentId();
        List<ModelCustomConfigDomain> modelCustomConfigDomainList = flowReModelCustomConfigRepository.listModelConfigByDeployIdAndType(deploymentId,
                nodeCode, idea);
        if (Objects.nonNull(modelCustomConfigDomainList) && modelCustomConfigDomainList.size() > 0){
            for (ModelCustomConfigDomain modelCustomConfigDomain : modelCustomConfigDomainList) {
                String isRequiredComment = modelCustomConfigDomain.getConfig();
                if (Objects.equals(isRequiredComment,"1")){
                    flag = true;
                }
            }
        }
        return flag;
    }

    public void executeNodeOperEvent(String taskId,String userCode, NodeOperEnum nodeOperEnum, NodeOperEventTypeEnum nodeOperEventTypeEnum) throws Exception {
        FlowTaskTraceVo flowTaskTraceVo = flowTaskTraceRepository.getTaskTraceByTaskId(taskId);
        if (Objects.nonNull(flowTaskTraceVo)){
            NodeOperEventReq nodeOperEventReq = new NodeOperEventReq();
            nodeOperEventReq.setNodeCode(flowTaskTraceVo.getActivityId());
            nodeOperEventReq.setNodeOperType(nodeOperEnum.name());
            nodeOperEventReq.setProcessInstanceId(flowTaskTraceVo.getProcessInstanceId());
            nodeOperEventReq.setEventType(nodeOperEventTypeEnum.name());
            nodeOperEventReq.setUserCode(userCode);
            nodeOperEventReq.setTaskId(taskId);
            nodeOperEventCaller.call(nodeOperEventReq);
        }
    }
}
